<template>
  <div
    class="scenes"
    style="
      position: fixed;
      top: 0;
      left: 0;
      z-index: 10;
      pointer-events: none;
      transition: all 1s ease-in-out;
    "
    :style="`transform: translate3d(0, ${index * -100}vh, 0)`"
  >
    <div
      v-for="(item, index) in scenes"
      :key="index"
      style="width: 100vw; height: 100vh"
    >
      <h1 style="padding: 100px 50px; font-size: 24px; color: #fff">
        {{ item.txt }}
      </h1>
    </div>
  </div>
</template>

<script setup>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
import { Water } from "three/examples/jsm/objects/Water2";
import gsap from "gsap";
import { ref } from "vue";

// 初始化场景
const scene = new THREE.Scene();

// 初始化相机
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
camera.position.set(-3.23, 2.98, 4.06);
camera.updateProjectionMatrix();

// 初始化渲染器
const renderer = new THREE.WebGLRenderer({
  antialias: true, // 抗锯齿
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
renderer.outputEncoding = THREE.sRGBEncoding; // 设置输出色域
renderer.toneMapping = THREE.ACESFilmicToneMapping; // 设置色调映射
renderer.toneMappingExposure = 0.5; // 设置色调映射曝光度
renderer.shadowMap.enabled = true; // 开启阴影

// 初始化控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(-8, 2, 0);
controls.enableDamping = true;

// 初始化 loader
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("./draco/");
const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(dracoLoader);

// 加载环境纹理
const rgbeLoader = new RGBELoader();
rgbeLoader.load("./textures/sky.hdr", (texture) => {
  texture.mapping = THREE.EquirectangularReflectionMapping;
  scene.background = texture;
  scene.environment = texture;
});

// 加载模型
gltfLoader.load("./models/scene.glb", (gltf) => {
  const model = gltf.scene;
  const plane = gltf.scene.getObjectByName("Plane");
  plane.visible = false;
  model.traverse((child) => {
    if (!child.isMesh) return;
    child.castShadow = true; // 开启阴影
    child.receiveShadow = true; // 开启接收阴影
  });
  scene.add(model);
});

// 创建水面
const waterGeometry = new THREE.CircleGeometry(300, 32);
const water = new Water(waterGeometry, {
  textureWidth: 1024,
  textureHeight: 1024,
  color: 0xeeffff,
  flowDirection: new THREE.Vector2(1, 1),
  scale: 100,
});
water.rotation.x = -Math.PI / 2;
water.position.y = -0.5;
scene.add(water);

// 添加平行光
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(0, 50, 0);
scene.add(light);

// 添加点光源
const pointLight = new THREE.PointLight(0xffffff, 50);
pointLight.position.set(0.1, 1.6, 0);
pointLight.castShadow = true; // 开启阴影
scene.add(pointLight);

// 创建点光源组
const pointLightGroup = new THREE.Group();
pointLightGroup.position.set(-8, 2.5, -1.5);
const radius = 3;
const pointLightArr = [];
for (let i = 0; i < 3; i++) {
  // 创建球体作为灯泡
  const sphere = new THREE.Mesh(
    new THREE.SphereGeometry(0.2, 32, 32),
    new THREE.MeshStandardMaterial({
      color: 0xffffff,
      emissive: 0xffffff,
      emissiveIntensity: 10, // 光源强度
    })
  );

  sphere.position.set(
    radius * Math.cos((i * 2 * Math.PI) / 3),
    Math.cos((i * 2 * Math.PI) / 3),
    radius * Math.sin((i * 2 * Math.PI) / 3)
  );

  pointLightArr.push(sphere);

  const pointLight = new THREE.PointLight(0xffffff, 50);

  sphere.add(pointLight);

  pointLightGroup.add(sphere);
}
scene.add(pointLightGroup);

// 使用补间动画，从0到2Π，让点光源组绕Y轴旋转
const options = {
  angle: 0,
};
gsap.to(options, {
  angle: 2 * Math.PI,
  duration: 10,
  repeat: -1,
  ease: "linear",
  onUpdate: () => {
    pointLightGroup.rotation.y = options.angle;
    pointLightArr.forEach((item, index) => {
      item.position.set(
        radius * Math.cos((index * 2 * Math.PI) / 3),
        Math.cos((index * 2 * Math.PI) / 3 + options.angle * 5),
        radius * Math.sin((index * 2 * Math.PI) / 3)
      );
    });
  },
});

const render = () => {
  requestAnimationFrame(render);
  renderer.render(scene, camera);
  controls && controls.update();
};

render();

const index = ref(0);

const scenes = [
  {
    txt: "场景1文本",
    callback: () => {
      // 执行函数切换场景
      translateCamera(
        new THREE.Vector3(-3.23, 2.98, 4.06),
        new THREE.Vector3(-8, 2, 0)
      );
    },
  },
  {
    txt: "场景222",
    callback: () => {
      // 执行函数切换场景
      translateCamera(new THREE.Vector3(7, 0, 23), new THREE.Vector3(0, 0, 0));
    },
  },
  {
    txt: "333333",
    callback: () => {
      // 执行函数切换场景
      translateCamera(new THREE.Vector3(10, 3, 0), new THREE.Vector3(5, 2, 0));
    },
  },
  {
    txt: "~~~~~~~~~~~",
    callback: () => {
      // 执行函数切换场景
      translateCamera(new THREE.Vector3(7, 0, 23), new THREE.Vector3(0, 0, 0));
      makeHeart();
    },
  },
  {
    txt: "-----------",
    callback: () => {
      // 执行函数切换场景
      translateCamera(
        new THREE.Vector3(-20, 1.3, 6.6),
        new THREE.Vector3(5, 2, 0)
      );
    },
  },
];

let isAnimate = false;

// 使用补间动画移动相机
const timeLine1 = gsap.timeline();
const timeline2 = gsap.timeline();

// 定义相机移动函数
const translateCamera = (position, target) => {
  timeLine1.to(camera.position, {
    duration: 1,
    x: position.x,
    y: position.y,
    z: position.z,
    ease: "power2.inOut",
  });

  timeline2.to(controls.target, {
    duration: 1,
    x: target.x,
    y: target.y,
    z: target.z,
    ease: "power2.inOut",
  });
};

window.addEventListener("wheel", (event) => {
  if (isAnimate) return;
  isAnimate = true;
  if (event.deltaY > 0) {
    index.value++;
    if (index.value >= scenes.length - 1) {
      index.value = 0;
      restoreHeart();
    }
    scenes[index.value].callback();
    setTimeout(() => {
      isAnimate = false;
    }, 1000);
  }
});

// 实例化创建星星
const starsInstance = new THREE.InstancedMesh(
  new THREE.SphereGeometry(0.1, 32, 32),
  new THREE.MeshStandardMaterial({
    color: 0xffffff,
    emissive: 0xffffff,
    emissiveIntensity: 10,
  }),
  100
);

// 星星随机分布到天上
const startArr = [];
const endArr = [];

for (let i = 0; i < 100; i++) {
  const x = Math.random() * 100 - 50;
  const y = Math.random() * 100 - 50;
  const z = Math.random() * 100 - 50;
  startArr.push(new THREE.Vector3(x, y, z));

  const matrix = new THREE.Matrix4();
  matrix.setPosition(x, y, z);
  starsInstance.setMatrixAt(i, matrix);
}
scene.add(starsInstance);

// 创建爱心路径（贝塞尔曲线）
const heartShape = new THREE.Shape();
heartShape.moveTo(25, -25);
heartShape.bezierCurveTo(25, -25, 20, 0, 0, 0);
heartShape.bezierCurveTo(-30, 0, -30, -35, -30, -35);
heartShape.bezierCurveTo(-30, -55, -10, -77, 25, -95);
heartShape.bezierCurveTo(60, -77, 80, -55, 80, -35);
heartShape.bezierCurveTo(80, -35, 80, 0, 50, 0);
heartShape.bezierCurveTo(35, 0, 25, -25, 25, -25);

// 根据贝塞尔曲线创建爱心
const center = new THREE.Vector3(0, 10, 8);
for (let i = 0; i < 100; i++) {
  const poiont = heartShape.getPoint(i / 100);
  endArr.push(
    new THREE.Vector3(
      poiont.x * 0.1 + center.x,
      poiont.y * 0.1 + center.y,
      center.z
    )
  );
}

// 创建爱心动画
const makeHeart = () => {
  const params = {
    time: 0,
  };
  gsap.to(params, {
    time: 1,
    duration: 1,
    ease: "linear",
    onUpdate: () => {
      for (let i = 0; i < 100; i++) {
        const x = startArr[i].x + (endArr[i].x - startArr[i].x) * params.time;
        const y = startArr[i].y + (endArr[i].y - startArr[i].y) * params.time;
        const z = startArr[i].z + (endArr[i].z - startArr[i].z) * params.time;
        const matrix = new THREE.Matrix4();
        matrix.setPosition(x, y, z);
        starsInstance.setMatrixAt(i, matrix);
      }
      starsInstance.instanceMatrix.needsUpdate = true;
    },
  });
};

// 还原爱心动画
const restoreHeart = () => {
  const params = {
    time: 0,
  };
  gsap.to(params, {
    time: 1,
    duration: 1,
    ease: "linear",
    onUpdate: () => {
      for (let i = 0; i < 100; i++) {
        const x = endArr[i].x + (startArr[i].x - endArr[i].x) * params.time;
        const y = endArr[i].y + (startArr[i].y - endArr[i].y) * params.time;
        const z = endArr[i].z + (startArr[i].z - endArr[i].z) * params.time;
        const matrix = new THREE.Matrix4();
        matrix.setPosition(x, y, z);
        starsInstance.setMatrixAt(i, matrix);
      }
      starsInstance.instanceMatrix.needsUpdate = true;
    },
  });
};
</script>

<style scoped>
canvas {
  width: 100vw;
  height: 100vh;
  position: fixed;
  top: 0;
  left: 0;
}
</style>
